<!doctype html>
<html lang="en" class="page-type-section">
<head prefix="og: http://ogp.me/ns#">
<meta charset="utf-8">
<title>Bean的包装 - FreeMarker 手册</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="format-detection" content="telephone=no">
<meta property="og:site_name" content="FreeMarker 手册">
<meta property="og:title" content="Bean的包装">
<meta property="og:locale" content="en_US">
<meta property="og:url" content="http://freemarker.org/docs/pgui_misc_beanwrapper.html">
<link rel="canoical" href="http://freemarker.org/docs/pgui_misc_beanwrapper.html">
<link rel="icon" href="favicon.png" type="image/png">
<link rel="stylesheet" type="text/css" href="docgen-resources/docgen.min.css">
</head>
<body itemscope itemtype="https://schema.org/Code">
    <meta itemprop="url" content="http://freemarker.org/docs/">
    <meta itemprop="name" content="FreeMarker 手册">

  <!--[if lte IE 9]>
  <div style="background-color: #C00; color: #fff; padding: 12px 24px;">Please use a modern browser to view this website.</div>
  <![endif]--><div class="header-top-bg"><div class="site-width header-top"><a class="logo" href="http://freemarker.org" role="banner">            <img itemprop="image" src="logo.png" alt="FreeMarker">
</a><ul class="tabs"><li><a href="http://freemarker.org/">Home</a></li><li class="current"><a href="index.html">Manual</a></li><li><a class="external" href="http://freemarker.org/docs/api/index.html">Java API</a></li></ul><ul class="secondary-tabs"><li><a class="tab icon-heart" href="http://freemarker.org/contribute.html" title="Contribute"><span>Contribute</span></a></li><li><a class="tab icon-bug" href="https://sourceforge.net/p/freemarker/bugs/new/" title="Report a Bug"><span>Report a Bug</span></a></li><li><a class="tab icon-download" href="http://freemarker.org/freemarkerdownload.html" title="Download"><span>Download</span></a></li></ul></div></div><div class="header-bottom-bg"><div class="site-width search-row"><a href="toc.html" class="navigation-header">Manual</a><div class="navigation-header"></div></div><div class="site-width breadcrumb-row"><ul class="breadcrumb" itemscope itemtype="http://schema.org/BreadcrumbList"><li class="step-0" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="toc.html"><span itemprop="name">FreeMarker 手册</span></a></li><li class="step-1" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="pgui.html"><span itemprop="name">程序开发指南</span></a></li><li class="step-2" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="pgui_misc.html"><span itemprop="name">其它</span></a></li><li class="step-3" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="pgui_misc_beanwrapper.html"><span itemprop="name">Bean的包装</span></a></li></ul><div class="bookmarks" title="Bookmarks"><span class="sr-only">Bookmarks:</span><ul class="bookmark-list"><li><a href="alphaidx.html">Alpha. index</a></li><li><a href="gloss.html">Glossary</a></li><li><a href="dgui_template_exp.html#exp_cheatsheet">Expressions</a></li><li><a href="ref_builtins_alphaidx.html">?builtins</a></li><li><a href="ref_directive_alphaidx.html">#directives</a></li><li><a href="ref_specvar.html">.spec_vars</a></li><li><a href="app_faq.html">FAQ</a></li></ul></div></div></div>    <div class="main-content site-width">
      <div class="content-wrapper">
  <div id="table-of-contents-wrapper" class="col-left">
      <script>var breadcrumb = ["FreeMarker 手册","程序开发指南","其它","Bean的包装"];</script>
      <script src="toc.js"></script>
      <script src="docgen-resources/main.min.js"></script>
  </div>
<div class="col-right"><div class="page-content"><div class="page-title"><div class="pagers top"><a class="paging-arrow previous" href="pgui_misc_multithreading.html"><span>Previous</span></a><a class="paging-arrow next" href="pgui_misc_logging.html"><span>Next</span></a></div><div class="title-wrapper">
<h1 class="content-header header-section1" id="pgui_misc_beanwrapper" itemprop="headline">Bean的包装</h1>
</div></div><div class="page-menu">
<div class="page-menu-title">Page Contents</div>
<ul><li><a class="page-menu-link" href="#beanswrapper_hash" data-menu-target="beanswrapper_hash">模板哈希表模型功能(TemplateHashModel functionality)</a></li><li><a class="page-menu-link" href="#autoid_47" data-menu-target="autoid_47">说一点安全性</a></li><li><a class="page-menu-link" href="#autoid_48" data-menu-target="autoid_48">模板标量模型功能(TemplateScalarModel functionality)</a></li><li><a class="page-menu-link" href="#autoid_49" data-menu-target="autoid_49">模板数字模型功能(TemplateNumberModel functionality)</a></li><li><a class="page-menu-link" href="#autoid_50" data-menu-target="autoid_50">模板集合模型功能(TemplateCollectionModel functionality)</a></li><li><a class="page-menu-link" href="#autoid_51" data-menu-target="autoid_51">模板序列模型功能(TemplateSequenceModel functionality)</a></li><li><a class="page-menu-link" href="#beanswrapper_method" data-menu-target="beanswrapper_method">模板方法模型功能(TemplateMethodModel functionality)</a></li><li><a class="page-menu-link" href="#autoid_52" data-menu-target="autoid_52">解包规则</a></li><li><a class="page-menu-link" href="#autoid_53" data-menu-target="autoid_53">访问静态方法</a></li><li><a class="page-menu-link" href="#jdk_15_enums" data-menu-target="jdk_15_enums">访问枚举类型</a></li></ul> </div>  <div class="callout note">
    <strong class="callout-label">Note:</strong>

          <p>直接使用 <code class="inline-code">BeansWrapper</code> 是不推荐的。
		  而可以使用它的子类 <code class="inline-code">DefaultObjectWrapper</code> 
		  来代替，要确保它的 <code class="inline-code">incompatibleImprovements</code> 
		  属性至少是2.3.22。<code class="inline-code">DefaultObjectWrapper</code> 
		  给出了干净的数据模型(很少的容易混淆的多类型的FTL值)而且通常速度很快。<a href="pgui_datamodel_objectWrapper.html#pgui_datamodel_defaultObjectWrapper">关于更多
          DefaultObjectWrapper 可以参看这里...</a></p>
          </div>
<p><code class="inline-code">freemarker.ext.beans.BeansWrapper</code> 是一个<a href="pgui_datamodel_objectWrapper.html">对象包装器</a>，
		最初加到FreeMarker中是为了将任意的POJO(Plan Old Java Objects，普通的Java对象)
		包装成 <code class="inline-code">TemplateModel</code> 接口类型。
		这样它就可以以正常的方式来进行处理，事实上 <code class="inline-code">DefaultObjectWrapper</code> 
		本身是 <code class="inline-code">BeansWrapper</code> 的扩展类。
		这里描述的所有东西对 <code class="inline-code">DefaultObjectWrapper</code> 都是适用的，
		除了 <code class="inline-code">DefaultObjectWrapper</code> 会用到 
		<code class="inline-code">freemarker.template.Simple<em class="code-color">Xxx</em></code> 
		类包装的<code class="inline-code">String</code>，<code class="inline-code">Number</code>，
		<code class="inline-code">Date</code>，<code class="inline-code">array</code>，
		<code class="inline-code">Collection</code>(如<code class="inline-code">List</code>)，
		<code class="inline-code">Map</code>，<code class="inline-code">Boolean</code> 和 
		<code class="inline-code">Iterator</code>对象，会用 <code class="inline-code">freemarker.ext.dom.NodeModel</code> 
		来包装W3C的DOM结点(<a href="xgui.html">更多关于包装的W3C DOM 可以参考这里...</a>)，
		所以上述这些描述的规则不适用。</p><p>当出现下面这些情况时，
		你会想使用 <code class="inline-code">BeansWrapper</code> 包装器来代替 
		<code class="inline-code">DefaultObjectWrapper</code>：</p><ul>
          <li>
            <p>在模板执行期间，数据模型中的 <code class="inline-code">Collection</code> 
			和 <code class="inline-code">Map</code> 应该被允许修改。
			(<code class="inline-code">DefaultObjectWrapper</code> 会阻止这样做，
			因为当它包装对象时创建了数据集合的拷贝，而这些拷贝都是只读的。)</p>
          </li>

          <li>
            <p>如果 <code class="inline-code">array</code>，<code class="inline-code">Collection</code> 
			和 <code class="inline-code">Map</code> 对象的标识符当在模板中被传递到被包装对象的方法时，
			必须被保留下来。也就是说，那些方法必须得到之前包装好的同类对象。</p>
          </li>

          <li>
            <p>如果在之前列出的Java API中的类(如 <code class="inline-code">String</code>，
			<code class="inline-code">Map</code>，<code class="inline-code">List</code> 等)应该在模板中可见。
			还有 <code class="inline-code">BeansWrapper</code>，默认情况下它们是不可见的，
			但是可以设置获取的可见程度(后面将会介绍)。请注意这是一个不好的实践，
			尽量去使用 <a href="ref_builtins.html">内建函数</a>
			(如<code class="inline-code">foo?size</code>，<code class="inline-code">foo?upper_case</code>，
			<code class="inline-code">foo?replace(&#39;_&#39;, &#39;-&#39;)</code> 等）来代替Java API的使用。</p>
          </li>
        </ul><p>下面是对 <code class="inline-code">BeansWrapper</code> 创建的 
		<code class="inline-code">TemplateModel</code> 对象进行的总结。为了后续的讨论，
		这里我们假设在包装之前对象都称为 <code class="inline-code">obj</code>，
		而包装的后称为 <code class="inline-code">model</code>。</p>
          



<h2 class="content-header header-section2" id="beanswrapper_hash">模板哈希表模型功能(TemplateHashModel functionality)</h2>


          <p>所有的对象都将被包装成 <code class="inline-code">TemplateHashModel</code> 类型，
		  进而可以获取出JavaBean对象中的属性和方法。这样，
		  就可以在模板中使用 <code class="inline-code">model.foo</code> 的形式来调用 
		  <code class="inline-code">obj.getFoo()</code> 方法或 <code class="inline-code">obj.isFoo()</code> 方法了。
		  (要注意公有的属性直接是不可见的，必须为它们编写getter方法才行)
		  公有方法通过哈希表模型来取得，就像模板方法模型那样，
		  因此可以使用 <code class="inline-code">model.doBar()</code> 来调用 
		  <code class="inline-code">object.doBar()</code>。下面我们来更多讨论一下方法模型功能。</p>

          <p>如果请求的键值不能映射到一个bean的属性或方法时，
		  那么框架将试图定位到&quot;通用的get方法&quot;，这个方法的签名是 
		  public <code class="inline-code"><em class="code-color">any-return-type</em> get(String)</code> 或 
		  public <code class="inline-code"><em class="code-color">any-return-type</em> get(Object)</code>，
		  使用请求键值来调用它们。请注意，这样就使得访问 <code class="inline-code">java.util.Map</code> 
		  和其他类似类型的键值对非常便利。只要map的键是 <code class="inline-code">String</code> 类型的，
		  属性和方法名可以在映射中查到。(有一种解决方法可以用来避免在映射中遮挡名称，请继续来阅读。)
		  要而且注意 <code class="inline-code">java.util.ResourceBundle</code> 对象的方法使用 
		  <code class="inline-code">getObject(String)</code> 方法作为通用的get方法。</p>

          <p>如果在 <code class="inline-code">BeansWrapper</code> 实例中调用了 
		  <code class="inline-code">setExposeFields(true)</code> 方法，那么它仍然会暴露出类的公有的，
		  非静态的变量，用它们作为哈希表的键和值。即如果 <code class="inline-code">foo</code> 
		  是类 <code class="inline-code">Bar</code> 的一个公有的，非静态的变量，而 
		  <code class="inline-code">bar</code> 是一个包装了 <code class="inline-code">Bar</code> 实例模板变量，
		  那么表达式 <code class="inline-code">bar.foo</code> 的值将会作为 <code class="inline-code">bar</code> 
		  对象中 <code class="inline-code">foo</code> 变量的值。所有这个类的超类中公有变量都会被暴露出来。</p>
        
          



<h2 class="content-header header-section2" id="autoid_47">说一点安全性</h2>


          <p>默认情况下，一些方法不能访问，它们被认为是模板中不安全的。
		  比如，不能使用同步方法(<code class="inline-code">wait</code>，<code class="inline-code">notify</code>，
		  <code class="inline-code">notifyAll</code>)，线程和线程组的管理方法(<code class="inline-code">stop</code>，
		  <code class="inline-code">suspend</code>，<code class="inline-code">resume</code>，<code class="inline-code">setDaemon</code>，
		  <code class="inline-code">setPriority</code>)，反射相关方法（<code class="inline-code">Field</code>，
		  <code class="inline-code">set<em class="code-color">Xxx</em></code> 方法，
		  <code class="inline-code">Method.invoke</code>，<code class="inline-code">Constructor.newInstance</code>，
		  <code class="inline-code">Class.newInstance</code>，<code class="inline-code">Class.getClassLoader</code>等)，
		  <code class="inline-code">System</code> 和 <code class="inline-code">Runtime</code> 类中各种有危险性的方法
		  (<code class="inline-code">exec</code>，<code class="inline-code">exit</code>，<code class="inline-code">halt</code>，
		  <code class="inline-code">load</code>等)。<code class="inline-code">BeansWrapper</code> 也有一些安全级别
		  (被称作&quot;方法暴露的级别&quot;），默认的级别被称作为 <code class="inline-code">EXPOSE_SAFE</code>，
		  它可能对大多数应用程序来说是适用的。没有安全保证的级别称作是 
		  <code class="inline-code">EXPOSE_ALL</code>，它允许你调用上述的不安全的方法。一个严格的级别是 
		  <code class="inline-code">EXPOSE_PROPERTIES_ONLY</code>，它只会暴露出bean属性的getters方法。
		  最后，一个称作是 <code class="inline-code">EXPOSE_NOTHING</code> 的级别，它不会暴露任何属性和方法。
		  这种情况下，你可以通过哈希表模型接口访问的那些数据只是map和资源包中的项，
		  还有，可以从通用 <code class="inline-code">get(Object)</code> 方法和 <code class="inline-code">get(String)</code> 
		  方法调用返回的对象，所提供的受影响的对象就有这样的方法。</p>
        
          



<h2 class="content-header header-section2" id="autoid_48">模板标量模型功能(TemplateScalarModel functionality)</h2>


          <p>对于 <code class="inline-code">java.lang.String</code> 对象的模型会实现 
		  <code class="inline-code">TemplateScalarModel</code> 接口，这个接口中的 
		  <code class="inline-code">getAsString()</code> 方法简单代替了 <code class="inline-code">toString()</code> 方法。
		  要注意把 <code class="inline-code">String</code> 对象包装到Bean包装器中，
		  要提供比它们作为标量时更多的功能：因为哈希表接口描述了上述所需功能，
		  那么包装 <code class="inline-code">String</code> 的模型也会提供访问所有 
		  <code class="inline-code">String</code> 的方法(<code class="inline-code">indexOf</code>，
		  <code class="inline-code">substring</code> 等)，尽管它们中很多都有内部的FreeMarker相同的实现，
		  最好使用它们(<code class="inline-code">s?index_of(n)</code>，<code class="inline-code">s[start..&lt;end]</code> 等)。</p>
        
          



<h2 class="content-header header-section2" id="autoid_49">模板数字模型功能(TemplateNumberModel functionality)</h2>


          <p>对于是 <code class="inline-code">java.lang.Number</code> 的实例对象的模型包装器，
		  它们实现了 <code class="inline-code">TemplateNumberModel</code> 接口，接口中的 
		  <code class="inline-code">getAsNumber()</code> 方法返回被包装的数字对象。
		  请注意把 <code class="inline-code">Number</code> 对象包装到Bean包装器中，
		  要提供比它们作为数字时更多的功能：因为哈希表接口描述了上述所需功能，
		  那么包装 <code class="inline-code">Number</code> 的模型也会提供访问所有他们的方法。</p>
        
          



<h2 class="content-header header-section2" id="autoid_50">模板集合模型功能(TemplateCollectionModel functionality)</h2>


          <p>对于本地的Java数组和其他所有实现了 <code class="inline-code">java.util.Collection</code> 
		  接口的类的模型包装器，都实现了 <code class="inline-code">TemplateCollectionModel</code> 接口，
		  因此也增强了使用 <code class="inline-code">list</code> 指令的附加功能。</p>
        
          



<h2 class="content-header header-section2" id="autoid_51">模板序列模型功能(TemplateSequenceModel functionality)</h2>


          <p>对于本地的Java数组和其他所有实现了 <code class="inline-code">java.util.List</code> 
		  接口的类的模型包装器，都实现了 <code class="inline-code">TemplateSequenceModel</code> 接口，
		  这样，它们之中的元素就可以使用 <code class="inline-code">model[i]</code> 这样的语法通过索引来访问了。
		  你也可以使用内建函数 <code class="inline-code">model?size</code> 来查询数组的长度和列表的大小。</p>

          <p>而且，所有的方法都可指定的一个单独的参数，从 
		  <code class="inline-code">java.lang.Integer</code>(即<code class="inline-code">int</code>, <code class="inline-code">long</code>, 
		  <code class="inline-code">float</code>, <code class="inline-code">double</code>，<code class="inline-code">java.lang.Object</code>，
		  <code class="inline-code">java.lang.Number</code>，<code class="inline-code">java.lang.Integer</code>)
		  中通过反射方法调用，这些类也实现了这个接口。
		  这就意味着你可以通过很方便的方式来访问被索引的bean属性：
		  <code class="inline-code">model.foo[i]</code> 将会翻译为 <code class="inline-code">obj.getFoo(i)</code>。</p>
        
          



<h2 class="content-header header-section2" id="beanswrapper_method">模板方法模型功能(TemplateMethodModel functionality)</h2>


          <p>一个对象的所有方法作为 <code class="inline-code">TemplateMethodModelEx</code> 对象的表述，
		  它们在对象模型的方法名中使用哈希表的键来访问。当使用 
		  <code class="inline-code">model.<em class="code-color">method</em>(<em class="code-color">arg1</em>,
          <em class="code-color">arg2</em>,
          <em class="code-color">...</em>)</code> 来调用方法时，形参被作为模板模型传递给方法。
		  方法首先不会包装它们，后面我们会说到解包的详细内容。
		  这些不被包装的参数之后被实际方法来调用。以防止方法被重载，
		  许多特定的方法将会被选择使用相同的规则，也就是Java编译器从一些重载的方法中选择一个方法。
		  以防止没有方法签名匹配传递的参数，或者没有方法可以被无歧义地选择，
		  将会抛出 <code class="inline-code">TemplateModelException</code> 异常。</p>

          <p>返回值类型为 <code class="inline-code">void</code> 的方法返回 
		  <code class="inline-code">TemplateModel.NOTHING</code>，那么它们就可以使用 
		  <code class="inline-code">${obj.method(args)}</code> 形式的语法被安全地调用。</p>

          <p><code class="inline-code">java.util.Map</code> 实例的模型仍然实现了 
		  <code class="inline-code">TemplateMethodModelEx</code> 接口，作为调用它们 
		  <code class="inline-code">get()</code> 方法的一种方式。正如前面所讨论的那样，
		  你可以使用哈希表功能来访问&quot;get&quot;方法，但是它有一些缺点：
		  因为第一个属性和方法名会被键名来检查，所以执行过慢；
		  属性，方法名相冲突的键将会被隐藏；最终这种方法中你只可使用 
		  <code class="inline-code">String</code> 类型的键。对比一下，调用 
		  <code class="inline-code">model(key)</code> 方法，将直接翻译为 
		  <code class="inline-code">model.get(key)</code>：因为没有属性和方法名的查找，
		  速度会很快；不容易被隐藏；最终对非字符串的键也能正常处理，
		  因为参数没有被包装，只是被普通的方法调用。实际上，
		  <code class="inline-code">Map</code> 中的 <code class="inline-code">model(key)</code> 和 
		  <code class="inline-code">model.get(key)</code> 是相等的，只是写起来很短罢了。</p>

          <p><code class="inline-code">java.util.ResourceBundle</code> 类的模型也实现了 
		  <code class="inline-code">TemplateMethodModelEx</code> 接口，
		  作为一种访问资源和信息格式化的方便形式。对资源包的单参数调用，
		  将会取回名称和未包装参数的 <code class="inline-code">toString()</code> 方法返回值一致的资源。
		  对资源包的多参数调用的情况和单参数一样，但是它会将参数作为格式化的模式传递给 
		  <code class="inline-code">java.text.MessageFormat</code>，在第二个和后面的作为格式化的参数中使用未包装的值。
		  <code class="inline-code">MessageFormat</code> 对象将会使用它们原本的本地化资源包来初始化。</p>
        
          



<h2 class="content-header header-section2" id="autoid_52">解包规则</h2>


          <p>当从模板中调用Java方法时，它的参数需要从模板模型转换回Java对象。
		  假设目标类型(方法常规参数被声明的类型)是用来 <code class="inline-code">T</code> 代表的，
		  下面的规则将会按下述的顺序进行依次尝试：</p>

          <ul>
            <li>
              <p>对包装器来说，如果模型是空模型，
			  就返回Java中的 <code class="inline-code">null</code>。</p>
            </li>

            <li>
              <p>如果模型实现了 <code class="inline-code">AdapterTemplateModel</code> 接口，
			  如果它是 <code class="inline-code">T</code> 的实例，
			  或者它是一个数字而且可以使用下面第三点描述的数字强制转换成 <code class="inline-code">T</code>，
			  那么 <code class="inline-code">model.getAdaptedObject(T)</code> 的结果会返回。
			  <span class="marked-for-programmers">由BeansWrapper创建的所有方法是AdapterTemplateModel的实现，
			  所以由BeansWrapper为基本的Java对象创建的展开模型通常不如初始的Java对象。</span></p>
            </li>

            <li>
              <p>如果模型实现了已经废弃的 <code class="inline-code">WrapperTemplateModel</code> 接口，
			  如果它是 <code class="inline-code">T</code> 的实例，
			  或者它是一个数字而且可以使用下面第二点描述的数字强制转换成 
			  <code class="inline-code">T</code> ，那么 <code class="inline-code">model.getWrappedObject()</code> 
			  方法的结果会返回。</p>
            </li>

            <li>
              <p>如果 <code class="inline-code">T</code> 是 <code class="inline-code">java.lang.String</code> 类型，
			  那么如果模型实现了 <code class="inline-code">TemplateScalarModel</code> 接口，它的字符串值将会返回。
              <span class="marked-for-programmers">请注意，如果模型没有实现接口，
			  我们不能尝试使用String.valueOf(model)方法自动转换模型到String类型。
			  这里不得不使用内建函数?string明确地用字符串来处理非标量。</span></p>
            </li>

            <li>
              <p>如果 <code class="inline-code">T</code> 是原始的数字类型或者是可由 
			  <code class="inline-code">T</code> 指定的 <code class="inline-code">java.lang.Number</code> 
			  类型，还有模型实现了 <code class="inline-code">TemplateNumberModel</code> 接口，
			  如果它是 <code class="inline-code">T</code> 的实例或者是它的装箱类型
			  (如果 <code class="inline-code">T</code> 是原始类型)，那么它的数字值会返回。
			  否则，如果 <code class="inline-code">T</code> 是一个Java内建的数字类型
			  (原始类型或是 <code class="inline-code">java.lang.Number</code> 的标准子类，
			  包括 <code class="inline-code">BigInteger</code> 和 <code class="inline-code">BigDecimal</code>)，
			  类型 <code class="inline-code">T</code> 
			  的一个新对象或是它的装箱类型会由数字模型的适当强制的值来生成。</p>
            </li>

            <li>
              <p>如果 <code class="inline-code">T</code> 是 <code class="inline-code">boolean</code> 值或
              <code class="inline-code">java.lang.Boolean</code> 类型，模型实现了
              <code class="inline-code">TemplateBooleanModel</code> 接口，那么布尔值将会返回。</p>
            </li>

            <li>
              <p>如果 <code class="inline-code">T</code> 是
              <code class="inline-code">java.util.Map</code> 类型，模型实现了
              <code class="inline-code">TemplateHashModel</code> 接口，
			  那么一个哈希表模型的特殊Map表示对象将会返回。</p>
            </li>

            <li>
              <p>如果 <code class="inline-code">T</code> 是
              <code class="inline-code">java.util.List</code> 类型，模型实现了
              <code class="inline-code">TemplateSequenceModel</code> 接口，
			  那么一个序列模型的特殊List表示对象将会返回。</p>
            </li>

            <li>
              <p>如果 <code class="inline-code">T</code> 是
              <code class="inline-code">java.util.Set</code> 类型，模型实现了
              <code class="inline-code">TemplateCollectionModel</code> 接口，
			  那么集合模型的一个特殊Set表示对象将会返回。</p>
            </li>

            <li>
              <p>如果 <code class="inline-code">T</code> 是
              <code class="inline-code">java.util.Collection</code> 或
              <code class="inline-code">java.lang.Iterable</code> 类型，模型实现了
              <code class="inline-code">TemplateCollectionModel</code> 或
              <code class="inline-code">TemplateSequenceModel</code> 接口，
			  那么集合或序列模型(各自地)一个特殊的Set或List表示对象将会返回。</p>
            </li>

            <li>
              <p>如果 <code class="inline-code">T</code> 是Java数组类型，模型实现了 
			  <code class="inline-code">TemplateSequenceModel</code> 接口，
			  那么一个新的指定类型的数组将会创建，
			  它其中的元素使用数组的组件类型作为 <code class="inline-code">T</code>，
			  递归展开到数组中。</p>
            </li>

            <li>
              <p>如果 <code class="inline-code">T</code> 是 <code class="inline-code">char</code> 或
              <code class="inline-code">java.lang.Character</code> 类型，模型实现了
              <code class="inline-code">TemplateScalarModel</code> 接口，
			  它的字符串表示中包含精确的一个字符，那么一个
              <code class="inline-code">java.lang.Character</code> 类型的值将会返回。</p>
            </li>

            <li>
              <p>如果 <code class="inline-code">T</code> 定义的是 
			  <code class="inline-code">java.util.Date</code> 类型，模型实现了
              <code class="inline-code">TemplateDateModel</code> 接口，
			  而且它的日期值是 <code class="inline-code">T</code> 的实例，
			  那么这个日期值将会返回。</p>
            </li>

            <li>
              <p>如果模型是数字模型，而且它的数字值是 <code class="inline-code">T</code> 
			  的实例，那么数字值就会返回。<span class="marked-for-programmers">
			  你可以得到一个实现了自定义接口的
			  java.lang.Number类型的自定义子类，也许T就是那个接口。(*)</span></p>
            </li>

            <li>
              <p>如果模型是日期类型，而且它的日期值是 <code class="inline-code">T</code> 的实例，
			  那么日期值将会返回。<span class="marked-for-programmers">类似的考虑为(*)</span></p>
            </li>

            <li>
              <p>如果模型是标量类型，而且 <code class="inline-code">T</code> 
			  可以从 <code class="inline-code">java.lang.String</code> 类型来定义，
			  那么字符串值将会返回。<span class="marked-for-programmers">
			  这种情况涵盖T是java.lang.Object, 
			  java.lang.Comparable和java.io.Serializable类型。(**)</span></p>
            </li>

            <li>
              <p>如果模型是布尔类型，而且 <code class="inline-code">T</code> 
			  可以从 <code class="inline-code">java.lang.Boolean</code> 类型来定义，
			  那么布尔值将会返回。
			  <span class="marked-for-programmers">和(**)是相同的</span></p>
            </li>

            <li>
              <p>如果模型是哈希表类型，而且 <code class="inline-code">T</code> 
			  可以从 <code class="inline-code">freemarker.ext.beans.HashAdapter</code> 类型来定义，
			  那么一个哈希表适配器将会返回。
			  <span class="marked-for-programmers">和(**)是相同的</span></p>
            </li>

            <li>
              <p>如果模型是序列类型，而且 <code class="inline-code">T</code> 
			  可以从 <code class="inline-code">freemarker.ext.beans.SequenceAdapter</code> 类型来定义，
			  那么一个序列适配器将会返回。
			  <span class="marked-for-programmers">和(**)是相同的</span></p>
            </li>

            <li>
              <p>如果模型是集合类型，而且 <code class="inline-code">T</code> 
			  可以从 <code class="inline-code">freemarker.ext.beans.SetAdapter</code> 类型来定义，
			  那么集合的set适配器将会返回。
			  <span class="marked-for-programmers">和(**)是相同的</span></p>
            </li>

            <li>
              <p>如果模型是 <code class="inline-code">T</code> 的实例，那么模型本身将会返回。
			  <span class="marked-for-programmers">这种情况涵盖方法明确地声明一个 FreeMarker 特定模型接口，
			  而且允许返回指令，当java.lang.Object被请求时允许返回方法和转换的模型。</span></p>
            </li>

            <li>
              <p>意味着没有可能转换的异常被抛出。</p>
            </li>
          </ul>
        
          



<h2 class="content-header header-section2" id="autoid_53">访问静态方法</h2>


          

          <p>从 <code class="inline-code">BeansWrapper.getStaticModels()</code> 方法返回的
		  <code class="inline-code">TemplateHashModel</code> 
		  可以用来创建哈希表模型来访问任意类的静态方法和字段。</p>

          

<div class="code-wrapper"><pre class="code-block code-unspecified">BeansWrapper wrapper = BeansWrapper.getDefaultInstance();
TemplateHashModel staticModels = wrapper.getStaticModels();
TemplateHashModel fileStatics =
    (TemplateHashModel) staticModels.get(&quot;java.io.File&quot;);</pre></div>

          <p>之后就可以得到模板的哈希表模型，它会暴露所有 
		  <code class="inline-code">java.lang.System</code> 类的静态方法和静态字段
		  (final类型和非final类型)作为哈希表的键。
		  设想你已经将之前的模型放到根root模型中了：</p>

          

<div class="code-wrapper"><pre class="code-block code-unspecified">root.put(&quot;File&quot;, fileStatics);</pre></div>

          <p>从现在开始，你可以在模板中使用 <code class="inline-code">${File.SEPARATOR}</code> 
		  来插入文件分隔符，或者你可以列出所有文件系统中的根元素，通过：</p>

          

<div class="code-wrapper"><pre class="code-block code-template">&lt;#list File.listRoots() as fileSystemRoot&gt;...&lt;/#list&gt;</pre></div>

          <p>当然，你必须小心这个模型所带来的潜在的安全问题。</p>

          <p>你可以给模板作者完全的自由，
		  不管它们通过将静态方法的哈希表放到模板的根模型中，
		  来使用哪种类的静态方法，如用如下方式：</p>

          

<div class="code-wrapper"><pre class="code-block code-unspecified">root.put(&quot;statics&quot;, BeansWrapper.getDefaultInstance().getStaticModels());</pre></div>

          <p>如果它被用作是以类名为键的哈希表，
		  这个对象暴露的只是任意类的静态方法。那么你可以在模板中使用如 
		  <code class="inline-code">${statics[&quot;java.lang.System&quot;].currentTimeMillis()}</code> 
		  这样的表达式。请注意，这样会有更多的安全隐患，比如，
		  如果方法暴露级别对 <code class="inline-code">EXPOSE_ALL</code> 是很弱的，
		  那么某些人可以使用这个模型调用 <code class="inline-code">System.exit()</code> 方法。</p>

          <p>请注意，在上述的示例中，我们通常使用默认的 
		  <code class="inline-code">BeansWrapper</code> 实例。这是一个方便使用的静态包装器实例，
		  你可以在很多情况下使用。特别是你想修改一些属性
		  (比如模型缓存，安全级别，或者是空模型对象表示)时，
		  你也可以自由地来创建自己的 <code class="inline-code">BeansWrapper</code> 实例，
		  然后用它们来代替默认包装器。</p>
        
          



<h2 class="content-header header-section2" id="jdk_15_enums">访问枚举类型</h2>


          

          <p>在JRE 1.5版本之后，从方法 <code class="inline-code">BeansWrapper.getEnumModels()</code> 
		  返回的 <code class="inline-code">TemplateHashModel</code> 可以被用作创建访问枚举类型值的哈希表模型。
		  (试图在之前JRE中调用这个方法会导致 <code class="inline-code">UnsupportedOperationException</code> 异常。)</p>

          

<div class="code-wrapper"><pre class="code-block code-unspecified">BeansWrapper wrapper = BeansWrapper.getDefaultInstance();
TemplateHashModel enumModels = wrapper.getEnumModels();
TemplateHashModel roundingModeEnums =
    (TemplateHashModel) enumModels.get(&quot;java.math.RoundingMode&quot;);</pre></div>

          <p>这样你就可以得到模板哈希表模型，它暴露了 
		  <code class="inline-code">java.math.RoundingMode</code> 类所有枚举类型的值，
		  并把它们作为哈希表的键。设想你将之前的模型已经放入root模型中了：</p>

          

<div class="code-wrapper"><pre class="code-block code-unspecified">root.put(&quot;RoundingMode&quot;, roundingModeEnums);</pre></div>

          <p>现在开始，你可以在模板中使用表达式 
		  <code class="inline-code">RoundingMode.UP</code> 来引用枚举值 <code class="inline-code">UP</code>。</p>

          <p>你可以给模板作者完全的自由，不管它们使用哪种枚举类，
		  将枚举模型的哈希表放到模板的root模型中，可以这样来做：</p>

          

<div class="code-wrapper"><pre class="code-block code-unspecified">root.put(&quot;enums&quot;, BeansWrapper.getDefaultInstance().getEnumModels());</pre></div>

          <p>如果它被用作是类名作为键的哈希表，这个对象暴露了任意的枚举类。
		  那么可以在模板中使用如 
		  <code class="inline-code">${enums[&quot;java.math.RoundingMode&quot;].UP}</code> 的表达式。</p>

          <p>被暴露的枚举值可以被用作是标量(它们会委派它们的 
		  <code class="inline-code">toString()</code> 方法)，也可以用在相同或不同的比较中。</p>

          <p>请注意，在上述的例子中，我们通常使用默认的 
		  <code class="inline-code">BeansWrapper</code> 实例。这是一个方便使用的静态包装器实例，
		  你可以在很多情况下使用。特别是你想修改一些属性
		  (比如模型缓存，安全级别，或者是空模型对象表示)时，
		  你也可以自由地来创建自己的 <code class="inline-code">BeansWrapper</code> 实例，
		  然后用它们来代替默认包装器。</p>
        <div class="bottom-pagers-wrapper"><div class="pagers bottom"><a class="paging-arrow previous" href="pgui_misc_multithreading.html"><span>Previous</span></a><a class="paging-arrow next" href="pgui_misc_logging.html"><span>Next</span></a></div></div></div></div>      </div>
    </div>
<div class="site-footer"><div class="site-width"><div class="footer-top"><div class="col-left sitemap"><div class="column"><h3 class="column-header">Overview</h3><ul><li><a href="http://freemarker.org/index.html">What is FreeMarker?</a></li><li><a href="http://freemarker.org/freemarkerdownload.html">Download</a></li><li><a href="app_versions.html">Version history</a></li><li><a href="http://freemarker.org/history.html">About us</a></li><li><a itemprop="license" href="app_license.html">License</a></li></ul></div><div class="column"><h3 class="column-header">Handy stuff</h3><ul><li><a href="http://freemarker-online.kenshoo.com/">Try template online</a></li><li><a href="dgui_template_exp.html#exp_cheatsheet">Expressions cheatsheet</a></li><li><a href="ref_directive_alphaidx.html">#directives</a></li><li><a href="ref_builtins_alphaidx.html">?built_ins</a></li><li><a href="ref_specvar.html">.special_vars</a></li></ul></div><div class="column"><h3 class="column-header">Community</h3><ul><li><a href="https://github.com/nanlei/freemarker/tree/manual-zh-2.3-gae/src/manual">Chinese Manual on Github</a></li><li><a href="https://github.com/freemarker/freemarker">FreeMarker on Github</a></li><li><a href="https://twitter.com/freemarker">Follow us on Twitter</a></li><li><a href="https://sourceforge.net/p/freemarker/bugs/new/">Report a bug</a></li><li><a href="http://stackoverflow.com/questions/ask?tags=freemarker">Ask a question</a></li><li><a href="http://freemarker.org/mailing-lists.html">Mailing lists</a></li></ul></div></div><div class="col-right"><ul class="social-icons"><li><a class="github" href="https://github.com/freemarker/freemarker">Github</a></li><li><a class="twitter" href="https://twitter.com/freemarker">Twitter</a></li><li><a class="stack-overflow" href="http://stackoverflow.com/questions/ask?tags=freemarker">Stack Overflow</a></li></ul><a class="xxe" href="http://www.xmlmind.com/xmleditor/" rel="nofollow" title="Edited with XMLMind XML Editor"><span>Edited with XMLMind XML Editor</span></a></div></div><div class="footer-bottom"><p><span class="generated-for-product">Generated for: Freemarker 2.3.23</span><span class="last-updated"> Last generated:
<time itemprop="dateModified" datetime="2015-09-18T14:38:51Z" title="Friday, September 18, 2015 2:38:51 PM GMT">2015-09-18 14:38:51 GMT</time></span></p> <p class="copyright">
© <span itemprop="copyrightYear">1999</span>–2015
<a itemtype="http://schema.org/Organization" itemprop="copyrightHolder" href="http://freemarker.org">The FreeMarker Project</a>. All rights reserved. </p>
</div></div></div></body>
</html>
